#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include "evrc_alg.h"

#include <jni.h>
#include <assert.h>
#include <android/log.h>
#include <sys/time.h>

#define JNI_COPY    0
#define LOG_TAG "EVRC" 
#define LOGI(...) __android_log_print(ANDROID_LOG_DEBUG, "evrc", __VA_ARGS__)
#define JNIREG_CLASS "com/im/mdt/audio/EVRC"//指定要注册的类
//#define JNIREG_CLASS "com/csipsimple/audio/EVRC" //指定要注册的类

int Rvalue;
short Version;
short Enc_Size,Dec_Size;

char enstate[EVRC_ENC_STATIC_SIZE];  //每通道编码历史数据缓冲区
char destate[EVRC_DEC_STATIC_SIZE];  //每通道解码历史数据缓冲区
T_EvrcEncParam Encparam;
T_EvrcDecParam Decparam;

JNIEXPORT jint JNICALL GetVer(JNIEnv*  env, jclass  class)
{
    Version = EVRC_GetVer();
    LOGI("EVRC Version:%d\n",Version);
    return 0;
}
JNIEXPORT jint JNICALL Enc_Init(JNIEnv*  env, jclass  class)
{
    LOGI("init");

	Encparam.pEncChannelStAddr = enstate;
	Encparam.pVQEstate = NULL;
	Encparam.wChnSize = EVRC_ENC_STATIC_SIZE;
	Encparam.wParamSize = sizeof(T_EvrcEncParam);
	Encparam.wtty_encoder_option=0;
	Encparam.wMaxRate=4;
	Encparam.wMinRate=1;
	Encparam.wNoiseSuppress = 1;//噪声抑制标志。0代表关闭，1代表使用自带nr，2代表使用vqe。每次编码时检验，不通过函数返回-2。
	Encparam.wDownratemode=0;

	EVRC_Enc_Init(&Encparam);
    return 0;
}
JNIEXPORT jint JNICALL Dec_Init(JNIEnv*  env, jclass  class)
{
	Decparam.pDecChannelStAddr = destate;
	Decparam.wChnSize = EVRC_DEC_STATIC_SIZE;
	Decparam.wParamSize = sizeof(T_EvrcDecParam);
	Decparam.wBadFrameFlag = 0;
	Decparam.wtty_decoder_option=1;
	Decparam.wPostFilter=1;
	//Decparam.wBadFrameFlag = 0;
	EVRC_Dec_Init(&Decparam);
    return 0;
}
JNIEXPORT jint JNICALL Encoder_Proc(JNIEnv*  env, jclass  class,
		jshortArray	     pwInputPnt,
        jbyteArray 		 pucOutputPnt,
        jshort 			 pucOutLength)
{
	jshort *pwInput;
	jbyte*pucOutput;
	jint pwInputLength;//音频数据长度
	short pucOutputLength;//编码数据长度 如何计算 应该通过输入数据计算长度？？？

    //LOGI("!!!!!!!!!!!! to encode   ");
	pwInput = (*env)->GetShortArrayElements(env, pwInputPnt, JNI_COPY);
	pwInputLength = (*env)->GetArrayLength(env, pwInputPnt);
	pucOutput = (*env)->GetByteArrayElements(env, pucOutputPnt, JNI_COPY);
	pucOutputLength = (*env)->GetArrayLength(env, pucOutputPnt);

    //LOGI("begin to encode   %d\n",pwInputLength);

	Rvalue=EVRC_Encoder_Proc(pwInput,pwInputLength,pucOutput,&pucOutputLength,&Encparam);
	if(Rvalue) LOGI("EVRC_Encoder_Proc Error! %d\n",Rvalue);
    
//	int i =0;
//	for(i=0;i<2;i++)
//		LOGI("EVRC_Encoder_Proc pucOutput[%d] = %d\n",i,pucOutput[i]);
	//释放内存
	(*env)->ReleaseShortArrayElements(env, pwInputPnt, pwInput, JNI_COPY);
	(*env)->ReleaseByteArrayElements(env, pucOutputPnt, pucOutput, JNI_COPY);
    //LOGI("over for encode  %d ",pucOutputLength);

    return pucOutputLength;
}
JNIEXPORT jint JNICALL Decoder_Proc(JNIEnv*  env, jclass  class,
		jbyteArray      pucInputPnt,
		jint pucDataLen,
		jint pucDataTypeRate,
		jshortArray		pwOutputPnt)
{
	jbyte*pucInput;
	short pucInputLength;//EVRC音频数据长度
	jshort *pwOutput;
	short pwOutputLength;//解码数据长度

	pucInput = (*env)->GetByteArrayElements(env, pucInputPnt, JNI_COPY);
	pucInputLength = (*env)->GetArrayLength(env, pucInputPnt);
	pwOutput = (*env)->GetShortArrayElements(env, pwOutputPnt, JNI_COPY);

	Rvalue=EVRC_Decoder_Proc(pucInput,pucInputLength,pwOutput,&pwOutputLength,&Decparam);
	if(Rvalue) LOGI("EVRC_Decoder_Proc Error! %d\n",Rvalue);
	//释放内存
	(*env)->ReleaseByteArrayElements(env, pucInputPnt, pucInput, JNI_COPY);
	(*env)->ReleaseShortArrayElements(env, pwOutputPnt, pwOutput, JNI_COPY);
    return 0;
}

/*** Table of methods associated with a single class.*/ 
static JNINativeMethod gMethods[] = { 
{ "GetVer", "()I", (void *)GetVer},
{ "Enc_Init", "()I", (void *)Enc_Init},
{ "Encoder_Proc", "([S[BS)I", (void *)Encoder_Proc},
{ "Dec_Init", "()I", (void *)Dec_Init},
{ "Decoder_Proc", "([BII[S)I", (void *)Decoder_Proc}
};

/** Register several native methods for one class.*/ 
static int registerNativeMethods(JNIEnv* env, const char* className, 
JNINativeMethod* gMethods, int numMethods) 
{ 
    jclass clazz;
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL) { 
        return JNI_FALSE;
    } 
    if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) { 
        return JNI_FALSE; 
    } 
    return JNI_TRUE;
} 
/** Register native methods for all classes we know about.*/ 
static int registerNatives(JNIEnv* env)
{ 
    if  (!registerNativeMethods(env,  JNIREG_CLASS,  gMethods, sizeof(gMethods) / sizeof(gMethods[0])))
        return JNI_FALSE;
    return JNI_TRUE;
} 
/** Set some test stuff up.** Returns the JNI version on success, -1 on failure.*/ 
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) 
{ 
    JNIEnv* env = NULL;  
    jint result = -1;
    if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) { 
        return -1; 
    } 
    assert(env != NULL);  
    if (!registerNatives(env)) {//注册
        return -2;
    } 
    /* success -- return valid version number */ 
    result = JNI_VERSION_1_4;
    return result;
}
